import 'package:family_expense/features/bank_card/models/bank.dart';
import 'package:family_expense/features/bank_card/models/bank_card.dart';
import 'package:family_expense/features/income_expense/constants/income_expense_type.dart';
import 'package:family_expense/features/income_expense/constants/payment_type.dart';
import 'package:family_expense/features/journey/models/journey.dart';
import 'package:family_expense/features/journey/models/region.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

class JourneyIncomeExpenseDetail with ActionLogMixin {
  JourneyIncomeExpenseDetail({
    this.journey,
    this.id,
    this.location,
    this.amount,
    this.type = IncomeExpenseType.expense,
    this.paymentType = PaymentType.cash,
    this.currency,
    this.bankCard,
    this.details,
    this.remark,
    this.incomeExpenseDate,
    this.latitude,
    this.longitude,
    this.address,
    this.formattedAddress,
    this.province,
    this.city,
    this.district,
    User? createdBy,
    User? updatedBy,
    DateTime? dateCreated,
    DateTime? lastUpdated,
  }) {
    this.createdBy = createdBy;
    this.updatedBy = updatedBy;
    this.dateCreated = dateCreated;
    this.lastUpdated = lastUpdated;
  }

  factory JourneyIncomeExpenseDetail.fromJson(Map<String, dynamic> json) {
    return JourneyIncomeExpenseDetail(
      journey: Journey(
        id: json['journeyId']?.toString(),
        startDate: tryToConvert<DateTime>(
          json['journeyStartDate'],
          (p) => parseDate(p),
        ),
        endDate: tryToConvert<DateTime>(
          json['journeyEndDate'],
          (p) => parseDate(p),
        ),
        region: Region(title: json['regionTitle']?.toString()),
      ),
      id: json['id']?.toString(),
      location: json['location']?.toString(),
      amount: json['amount']?.toDouble(),
      type: json['type']?.toString(),
      paymentType: json['paymentType']?.toString(),
      currency: json['currency']?.toString(),
      bankCard: BankCard(
        id: json['bankCardId']?.toString(),
        name: json['bankCardName']?.toString(),
        isCreditCard: tryToConvert<bool>(
          json['bankCardIsCreditCard'],
          (p) => p as bool,
        ),
        bank: Bank(
          id: json['bankId']?.toString(),
          shortName: json['bankShortName']?.toString(),
          logoUrl: json['bankLogoUrl']?.toString(),
        ),
      ),
      details: json['details']?.toString(),
      remark: json['remark']?.toString(),
      incomeExpenseDate: tryToConvert<DateTime>(
        json['incomeExpenseDate'],
        (p) => parseDate(p),
      ),
      latitude: tryToConvert<double>(json['latitude'], (p) => p as double),
      longitude: tryToConvert<double>(json['longitude'], (p) => p as double),
      address: json['address']?.toString(),
      formattedAddress: json['formattedAddress']?.toString(),
      province: json['province']?.toString(),
      city: json['city']?.toString(),
      district: json['district']?.toString(),
      createdBy: tryToConvert<User>(json['createdBy'], (p) => User.fromJson(p)),
      updatedBy: tryToConvert<User>(json['updatedBy'], (p) => User.fromJson(p)),
      dateCreated: tryToConvert<DateTime>(
        json['dateCreated'],
        (p) => parseDate(p),
      ),
      lastUpdated: tryToConvert<DateTime>(
        json['lastUpdated'],
        (p) => parseDate(p),
      ),
    );
  }

  static const detailsMaxLength = 50;
  static const locationMaxLength = 30;
  static const currencyMaxLength = 10;
  static const remarkMaxLength = 100;

  Journey? journey;
  String? id;
  String? location;
  double? amount;
  String? type;
  String? paymentType;
  String? currency;
  BankCard? bankCard;
  String? details;
  String? remark;
  DateTime? incomeExpenseDate;
  double? latitude; // 坐标纬度，因为记录的海外地区，此处为标准GPS坐标。
  double? longitude; // 坐标经度，因为记录的海外地区，此处为标准GPS坐标。
  String? address; // 根据经纬度从地图API获取的地址信息，由逗号间隔，如中国,浙江省,杭州市,萧山区,北干街道。
  String? formattedAddress; // 根据经纬度从地图API获取的格式化后的地址信息，如浙江省杭州市萧山区北干街道博奥路。
  String? province; // 根据经纬度从地图API获取的坐标点所在省名称。
  String? city; // 根据经纬度从地图API获取的坐标点所在城市名称。
  String? district; // 根据经纬度从地图API获取的坐标点所在区。

  Map<String, dynamic> toJson() {
    // Formatting amount in order to make sure the amount is positive number for income and negative number for expense.
    // Formats the date parameter to clear the time value.
    return {
      'journey': journey?.toJson(),
      'id': id,
      'location': location,
      'amount': type == IncomeExpenseType.income
          ? amount!.abs()
          : -amount!.abs(),
      'type': type,
      'paymentType': paymentType,
      'currency': currency,
      'bankCard': bankCard?.toJson(),
      'details': details,
      'remark': remark,
      'incomeExpenseDate': incomeExpenseDate.formatLongDateTime(dateOnly: true),
      'latitude': latitude,
      'longitude': longitude,
      'address': address,
      'formattedAddress': formattedAddress,
      'province': province,
      'city': city,
      'district': district,
    };
  }

  /// Checks if the input [detail] has the same values.
  bool equals(JourneyIncomeExpenseDetail? detail) {
    if (detail == null) {
      return false;
    }

    return journey?.id == detail.journey?.id &&
        id == detail.id &&
        location == detail.location &&
        amount == detail.amount &&
        type == detail.type &&
        paymentType == detail.paymentType &&
        currency == detail.currency &&
        bankCard?.id == detail.bankCard?.id &&
        details == detail.details &&
        remark == detail.remark &&
        incomeExpenseDate == detail.incomeExpenseDate;
  }

  JourneyIncomeExpenseDetail clone() {
    return JourneyIncomeExpenseDetail(
      journey: journey?.clone(),
      id: id,
      location: location,
      amount: amount,
      type: type,
      paymentType: paymentType,
      currency: currency,
      bankCard: bankCard?.id != null ? bankCard!.clone() : null,
      details: details,
      remark: remark,
      incomeExpenseDate: incomeExpenseDate,
      latitude: latitude,
      longitude: longitude,
      address: address,
      formattedAddress: formattedAddress,
      province: province,
      city: city,
      district: district,
      createdBy: createdBy,
      dateCreated: dateCreated,
      updatedBy: updatedBy,
      lastUpdated: lastUpdated,
    );
  }
}
